import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

public class GeneralEventProcessor extends DrawObjectEventProcessor
{
    // CALL METHODS OF THIS "GENERAL" EVENT PROCESSOR FIRST!
    // (sets some flags and objects required by the specialized DrawObjectEventProcessors!)

    /*
    Convention:
    
    Please check conditions in the following orders:
    
    KEYBOARD:
    
    if (MultiSelectionExisting)
    else if (DEFINED(SingleSelectedObject))
    else if (DEFINED(NearObject))
    else
    
    MOUSE:
    
    move
    drag
    left click
    right click
    left press
    right press
    no button
    
    MOUSE: key presses are to be checked in same if (MouseEventProcessor.[...]) line,
    after mouse checks.
    
    Update stuff, like resetting values, is to be done at very end of
    TryProcessUserMouseAction(), if possible.
     
    */

    private void CreateDrawObject(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage Objects)
    {
        Point PlacePos = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()))); // where to place new DrawObject

        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_C))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("Node", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_F))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("CommentField", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_L))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("LearningNeuron", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_N))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("Neuron", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_S))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("SampleAndHold", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_T))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("TextField", PlacePos, null);
        }
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_V))
        {
            if (!(Objects.IsObjectAtPoint(PlacePos)))
                Objects.AddObject("VisualField", PlacePos, null);
        }
    }

    @Override
    public void TryProcessUserKeyboardAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
    {
        if (!(KeyboardEventsToBeProcessed(GUIElements)))
            return;

        // ****************************************************************
        // Del (delete DrawObject)
        if (KeyEventProcessor.IsKeyCodePressed(0x7f))
        {
            int DrawObjectCountOld = ObjectStorage.GetDrawObjectCount();

            if (MultiSelectionExisting)
            {
                ArrayList<DrawObject> MultiSelectionObjects = ObjectStorage.GetMultiSelectionObjects();

                ObjectStorage.DeleteObjects(MultiSelectionObjects);
                ObjectStorage.DeleteUnnecessaryObjects();
            }
            else if (DEFINED(NearObject))
            {
                if (NearObject.CanBeDeletedByUser())
                {
                    ObjectStorage.DeleteObject(NearObject);
                    ObjectStorage.DeleteUnnecessaryObjects(); // leak here for sure
                }
            }

            if (ObjectStorage.GetDrawObjectCount() != DrawObjectCountOld)
            {
                GUIElements.GetMainWindow().DoRedraw();
            }
        }
        // ****************************************************************
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_D) &&
            KeyEventProcessor.IsControlPressed())
        {
            int SpawnCount = 0;
            if (MultiSelectionExisting)
            {
                String SpawnCountString = Tools.ShowInputDialog("Duplicate how often?\r\nEnter positive number to spawn to the right, negative number to spawn down.");
                if (SpawnCountString != null && SpawnCountString.length() >= 1)
                {
                    try
                    {
                        SpawnCount = Integer.parseInt(SpawnCountString);
                    }
                    catch (Exception e)
                    {
                        // probably NumberFormatException
                    }
                }
                if (SpawnCount >= -1000000 && SpawnCount <= 1000000 && SpawnCount != 0)
                {
                    ObjectStorage.SaveMultiSelectionToFile("./NCIDE_duplicate.dat", new LoadSaveDataEx(true, "", "", ZoomManager.GetZoomFactor()));

                    Rectangle MultiSelectionRectangle = ObjectStorage.GetMultiSelectionRectangle(
                        ObjectStorage.GetMultiSelectionObjects()
                    );

                    int GridSizex = 50; // TODO: don't hard code
                    int GridSizey = 50; // TODO: don't hard code

                    int Movex = MultiSelectionRectangle.width - (MultiSelectionRectangle.width % GridSizex);
                    int Movey = MultiSelectionRectangle.height - (MultiSelectionRectangle.height % GridSizey);

                    ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();

                    for (int s = 0; s < Math.abs(SpawnCount); s++)
                    {
                        int DrawObjectCountOld = ObjectStorage.GetDrawObjectCount();

                        ObjectStorage.LoadAdditionalFromFile("./NCIDE_duplicate.dat");

                        int DrawObjectCountNew = ObjectStorage.GetDrawObjectCount();

                        for (int i = DrawObjectCountOld; i < DrawObjectCountNew; i++)
                            ObjectStorage.SetPartOfMultiSelection(i);

                        Point MoveAmount;

                        if (SpawnCount >= 0)
                            MoveAmount = new Point((int) ((s + 1) * Movex / GridSizex) * GridSizex + (s + 1) * GridSizex, 0); // round down to next Grid line at left
                        else
                            MoveAmount = new Point(0, (int) ((s + 1) * Movey / GridSizey) * GridSizey + (s + 1) * GridSizey); // round down to next Grid line above

                        ObjectStorage.MoveMultiSelection(MoveAmount);
                        ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();
                    }

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }
            else
            {
                GUIElements.GetMainWindow().GetTitleBarInfo().AddInfoText("Multi-select objects to duplicate!", true, false, false, false);
            }
        }
        // ****************************************************************
        // space (manually excite DrawObject(s))
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_SPACE))
        {
            if (IOProgram.IsExecuted())
            {
                if (MultiSelectionExisting)
                {
                    ArrayList<DrawObject> MultiSelectionObjects = ObjectStorage.GetMultiSelectionObjects();

                    ObjectStorage.ExciteMultipleObjects(MultiSelectionObjects);
                }
                else if (DEFINED(NearObject))
                {
                    NearObject.AddExcitementForNextTick(1.0);
                }

                // don't redraw manually here, IO program execution causes this anyway!
                // GUIElements.GetMainWindow().DoRedraw();
            }
        }

        return;
    }

    @Override
    public void TryProcessUserMouseAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
    {
        if (!(MouseEventsToBeProcessed(GUIElements)))
            return;

        // update flags etc. automatically (could use some CPU time, but negligible here)
        MultiSelectionExisting = ObjectStorage.IsMultiSelectionExisting();

        // ****************************************************************
        if (MouseEventProcessor.IsMouseMoved())
        {
            NearObject = ObjectStorage.TrySelectNearObject(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));
        }
        // ****************************************************************
        if (MouseEventProcessor.IsLeftButtonClicked() &&
            KeyEventProcessor.AnyKeyPressed() &&
            NOT(MultiSelectionExisting))
        {
            CreateDrawObject(GUIElements, KeyEventProcessor, MouseEventProcessor, ObjectStorage);

            GUIElements.GetMainWindow().DoRedraw();

            MoveMousePosLast = UNDEFINED_POINT; // no button pressed, no moving!
        }
        // ****************************************************************
        if (MouseEventProcessor.NoButtonPressed())
        {
            if (NOT(MultiSelectionExisting) && DEFINED(NearObject))
            {
                if (NearObject != NearObjectLast)
                {
                    ObjectStorage.UnHighlightAllObjects();

                    NearObject.SetHighlighted(true);

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }
            else if (NOT(MultiSelectionExisting))
            {
                if (NearObject != NearObjectLast)
                {
                    ObjectStorage.UnHighlightAllObjects();

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }

            MoveMousePosLast = UNDEFINED_POINT; // no button pressed, no moving!

            NearObjectLast = NearObject;
        }

        return;
    }
}
